Skip to content

e2e viewer: bind any free port instead of crashing on a busy 8901 - #998

Merged
RhysSullivan merged 1 commit into
mainfrom
claude/quizzical-pike-94352e
Jun 13, 2026
Merged

e2e viewer: bind any free port instead of crashing on a busy 8901#998
RhysSullivan merged 1 commit into
mainfrom
claude/quizzical-pike-94352e

Conversation

@RhysSullivan

Copy link
Copy Markdown
Collaborator

What

The e2e runs viewer (cd e2e && bun run serve) pinned port 8901 with no error handler, so it hard-crashed on EADDRINUSE. That's exactly the collision the per-checkout port machinery (e2e/src/ports.ts) exists to prevent: two worktrees — or a leaked previous viewer — would wedge each other, and on a host where 8901 is otherwise held (e.g. a tailscale-bound listener) it couldn't start at all.

The viewer SPA was already port- and mount-agnostic (base: "./", relative fetches, trace-viewer link built from window.location.href). The only thing tied to a port was the static server that hosts it.

Change

e2e/scripts/serve.ts now:

  • Walks forward from 8901 to the next free port when the default is taken, and prints the actual bound URL (e2e viewer → http://localhost:<port>/).
  • Pins strictly when PORT=… is set explicitly — fails loudly with exit 1 if busy, matching the --strictPort rule documented in ports.ts.

Plus a RUNNING.md note so the behavior is discoverable.

Verified locally

On this host 8901 was already held on the tailscale interface, which made for a real collision test:

  • Walk-forwardport 8901 in use, trying 8902… → bound 8902; GET / → 200 (dir→index.html), GET /manifest.json → 200, correct body, gzip negotiation intact, range requests untouched.
  • Pinned-busyPORT=8901 → exit 1, e2e viewer: PORT=8901 is in use — free it or pick another port.
  • Gatesoxfmt --check ✓, oxlint --deny-warnings ✓, tsc --noEmit ✓.

No product behavior changes; this is dev-tooling for the test viewer, so there's no e2e scenario to attach.

The viewer's static server pinned port 8901 with no error handler, so it
hard-crashed on EADDRINUSE — exactly the collision the per-checkout port
machinery exists to prevent. Two worktrees, or a leaked previous viewer,
would wedge each other.

The server now walks forward from 8901 to the next free port and prints the
actual bound URL. An explicit PORT still pins strictly and fails loudly if
busy (the strictPort rule). The built SPA was already port- and
mount-agnostic (relative assets + hash routing), so whatever port the server
lands on just works in the browser.
@RhysSullivan
RhysSullivan merged commit 27da940 into main Jun 13, 2026
10 of 13 checks passed
@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Cloudflare preview

Torn down — the PR is closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant